package com.redside.webapp.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.dao.DataAccessException;
import org.springframework.validation.BindException;
import org.springframework.validation.Errors;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.AbstractWizardFormController;
import org.springframework.web.util.WebUtils;

import com.redside.Constants;
import com.redside.model.Business;
import com.redside.model.Complaint;
import com.redside.model.list.OptionsBean;
import com.redside.model.lookup.BusinessCatLkp;
import com.redside.service.BusinessManager;
import com.redside.service.ComplaintManager;
import com.redside.service.EmailManager;
import com.redside.service.OptionsBeanLookupManager;
import com.redside.view.BusinessAssociatorView;
import com.redside.webapp.validator.BusinessAssociatorValidator;

/**
 * @author pchapman
 * 
 */
public class BusinessAssociatorFormController extends
		AbstractWizardFormController {
	private final Log logger = LogFactory
			.getLog(BusinessAssociatorFormController.class);

	public BusinessAssociatorFormController() {
		setCommandName("associatorView");
		setCommandClass(BusinessAssociatorView.class);
		setSessionForm(true);
	}

	private ComplaintManager complaintManager;
	private BusinessManager businessManager;
	private OptionsBeanLookupManager optionsBeanManager;
	private EmailManager emailManager;

	// private Complaint complaint;

	protected Object formBackingObject(HttpServletRequest request)
			throws Exception {
		logger.debug("retrieving expectedComplaint with id: "
				+ request.getParameter("complaintId"));
		BusinessAssociatorView associatorView = new BusinessAssociatorView();
		// populate form if we have a complaintId
		if (!StringUtils.isEmpty((String) request.getParameter("complaintId"))) {
			try {
				Complaint complaint = complaintManager.get(Long.valueOf(request
						.getParameter("complaintId")));
				associatorView = (BusinessAssociatorView) this
						.convertComplaintToView(complaint,
								new BusinessAssociatorView());
				request.getSession()
						.setAttribute("initialcomplaint", complaint);
				logger
						.debug("============= Resetting complaintView ==============");
				request.getSession().setAttribute(
						"initialBusiness",
						this.convertComplaintToView(complaint,
								new BusinessAssociatorView()));
				logger.debug("WE ARE SETTING ASSOCIATORVIEW....."
						+ associatorView.getBusiness().getBusinessName());
				return associatorView;
			} catch (DataAccessException e) {
				e.printStackTrace();
			}
		}
		return new BusinessAssociatorView();
	}

	protected Map<String, List<?>> referenceData(HttpServletRequest request,
			Object command, Errors errors, int page) throws Exception {
		BusinessAssociatorView associatorView = (BusinessAssociatorView) command;
		Map<String, List<?>> associatorLists;
		request.getSession().setAttribute("countyList",
				optionsBeanManager.findAll(Constants.COUNTY_LIST));
		request.getSession().setAttribute(
				"businessCategoryList",
				optionsBeanManager.findAll(Constants.BUS_CAT_LIST, "0",
						"Select Business Category"));
		if (page == 0 && request.getParameter("_target0") != null) {
			associatorLists = new HashMap<String, List<?>>();
			// TODO set these with an Enumeration or something.
			List<OptionsBean> list = new ArrayList<OptionsBean>();
			list.add(new OptionsBean("contains", "Contains"));
			list.add(new OptionsBean("matches", "Matches"));
			list.add(new OptionsBean("starts", "Starts With"));
			list.add(new OptionsBean("ends", "Ends With"));
			associatorLists.put("wildcards", list);
			return associatorLists;
		}
		if (page == 1 && request.getParameter("_target1") != null) {
			associatorLists = new HashMap<String, List<?>>();
			request.getSession().setAttribute("businessList",
					businessManager.findByAssociation(associatorView));
			return associatorLists;
		}
		if (page == 4 && request.getParameter("_target4") != null) {
			associatorLists = new HashMap<String, List<?>>();
			if (associatorView.getBusiness().getId() != null
					&& StringUtils.isEmpty((String) request.getSession()
							.getAttribute("complaintList"))) {
				associatorLists.put("complaintList", complaintManager
						.findComplaintsForVerifyProcess(associatorView
								.getBusiness().getId()));
			}
			if (request.getSession().getAttribute("natureOfComplaintList") == null) {
				request.getSession().setAttribute(
						"natureOfComplaintList",
						optionsBeanManager.findAll(Constants.COMPLAINT_NATURE,
								"0", "Select One"));
			}
			if (request.getSession().getAttribute("nonActionableList") == null) {
				request.getSession().setAttribute(
						"nonActionableList",
						optionsBeanManager.findAll(Constants.NON_ACTIONABLE,
								"0", "Select Reason"));
			}
			return associatorLists;
		}

		return new HashMap<String, List<?>>();
	}

	protected void postProcessPage(HttpServletRequest request, Object command,
			Errors errors, int page) throws Exception {
		BusinessAssociatorView associatorView = (BusinessAssociatorView) command;
		request.removeAttribute("readonly");

		if (request.getParameter("_target0") != null) {
			logger.debug("Cancel Button...");
			logger.debug("----->resetting the complaint from session.");
			Complaint complaint = (Complaint) request.getSession()
					.getAttribute("initialcomplaint");
			associatorView = (BusinessAssociatorView) convertComplaintToView(
					complaint, associatorView);
			logger.debug("view reset to: "
					+ associatorView.getBusiness().getBusinessName());
			associatorView.getBusiness().setId(null);
		}

		if (page == 0 && request.getParameter("_target1") != null) {
			logger.debug("Submitting search from Step1 to Step2...");
		}

		if (page == 1 && request.getParameter("_target2") != null) {
			logger.debug("Search result page to Google Search...");
		}

		if (page == 1 && request.getParameter("_target3") != null) {
			validatePage(associatorView, errors, page, request);
			request.setAttribute("pageFrom", "1");
			logger.debug("\n----> adding new business?: "
					+ associatorView.isExistingBusiness());
			if (associatorView.isExistingBusiness()
					&& associatorView.getBusiness().getId() != null) {
				logger.debug("Step2 to Associate Existing Business...");
				request.setAttribute("readonly", "true");
				Business business = businessManager.get(associatorView
						.getBusiness().getId());
				if (business != null) {
					associatorView.setBusinessCategoryId(business
							.getBusinessCatLkp().getId());
				}
			} else {
				logger.debug("Search Result to Enter New Business...");
				request.removeAttribute("readonly");
				associatorView = (BusinessAssociatorView) convertComplaintToView(
						(Complaint) WebUtils.getSessionAttribute(request,
								"initialcomplaint"), associatorView);
				associatorView.getBusiness().setBusinessCatLkp(
						new BusinessCatLkp(Long.valueOf(0), ""));
				// associatorView.setBusinessCatLkp(null);
			}
		}

		if (page == 2 && request.getParameter("_target3") != null) {
			logger.debug("Adding New Google Business: "
					+ associatorView.getBusiness().getBusinessName());
			request.setAttribute("pageFrom", "2");
			if (request.getParameter("_target3").equals("Enter New Business")) {
				logger.debug("target from google: "
						+ request.getParameter("_target3"));
				associatorView = (BusinessAssociatorView) convertComplaintToView(
						(Complaint) WebUtils.getSessionAttribute(request,
								"initialcomplaint"), associatorView);
				associatorView.setBusinessCategoryId(Long.valueOf(0));
			}
			if (StringUtils.equals(request.getParameter("_target3"),
					"Use selected business")) {
				logger.debug("here is the business from associator: "
						+ associatorView.getBusiness().getBusinessName());
				logger.debug("here is the business from the form param: "
						+ request.getParameter("businessName"));
				Business gb = new Business();
				gb.setActive(true);
				gb.setParentAsContact(false);
				gb.setInViolation(false);
				gb.setBusinessName(request.getParameter("businessName"));
				gb.getAddress().setAddress1(
						request.getParameter("businessAddress1"));
				gb.getAddress().setCity(request.getParameter("businessCity"));
				gb.getAddress().setStateId(
						request.getParameter("businessState"));
				logger.debug("Here is the phone from associatorView: "
						+ request.getParameter("businessPhone"));
				String phone = StringUtils.deleteWhitespace(request
						.getParameter("businessPhone"));
				StringUtils.remove(phone, " ");
				logger.debug("Here is the phone from Google: " + phone);
				gb.setBusinessPhone(phone);
				gb.setBusinessCatLkp(null);
				/*
				 * String zip= new YahooZipLocator().getZipCode(gb);
				 * if(StringUtils.isNotBlank(zip)){
				 * gb.setBusinessZip(StringUtils.substringBefore(zip, "-"));
				 * gb.setBusinessZipExt(StringUtils.substringAfter(zip, "-")); }
				 */
				associatorView.setBusiness(gb);
				associatorView.setBusinessCategoryId(Long.valueOf(0));
			}
		}
		// google page: back button
		if (page == 2 && request.getParameter("_target1") != null) {
			logger.debug("Back Button from Google Page...");
			if (associatorView.getBusiness().getId() == null) {
				Complaint complaint = (Complaint) request.getSession()
						.getAttribute("initialcomplaint");
				associatorView = (BusinessAssociatorView) convertComplaintToView(
						complaint, associatorView);
			}
		}

		if (page == 3 && request.getParameter("_target4") != null) {
			logger.debug("Submitting Business from Step4 to Step5...");
			validatePage(associatorView, errors, page, request);

			if (associatorView.getBusinessCategoryId().intValue() != 0) {
				logger.debug("associatorView.busCatId: "
						+ associatorView.getBusinessCategoryId());
				associatorView.getBusiness().setBusinessCatLkp(
						new BusinessCatLkp(optionsBeanManager.findById(
								Constants.BUS_CAT_BEAN, associatorView
										.getBusinessCategoryId())));
			}

			if (associatorView.getBusiness().getAddress().getCountyId() == null
					|| associatorView.getBusiness().getAddress().getCountyId() != associatorView
							.getCountyId()) {
				associatorView.getBusiness().getAddress()
						.setCountyId(
								associatorView.getBusiness().getAddress()
										.getCountyId());
			}
			BusinessAssociatorView sessionView = (BusinessAssociatorView) WebUtils
					.getSessionAttribute(request, "initialBusiness");

			if (!StringUtils.equals(associatorView.getCountyId(), sessionView
					.getCountyId())) {
				emailManager.sendMail(Constants.TPEP_COMPLAINT, associatorView
						.getCountyId());

			}
			associatorView.getBusiness().setActive(true);
			associatorView.getBusiness().setParentAsContact(false);
			associatorView.getBusiness().setInViolation(false);
			associatorView.getBusiness().getAddress().setStateId("OR");
		}

		// back button from page 5 to 4
		if (page == 4 && request.getParameter("_target3") != null) {
			logger.debug("Back Button from Step5 to Step4...");
		}
		if (page == 4 && request.getParameter("_target5") != null) {
			logger.debug("Submitting From Step5 to Step6...");
			validatePage(associatorView, errors, page, request);
			if (associatorView.getNatureOfComplaintId() != null
					&& associatorView.getNatureOfComplaintId() > 0) {
				associatorView.setNatureOfComplaintText(optionsBeanManager
						.findById(Constants.COMPLAINT_NATURE_BEAN,
								associatorView.getNatureOfComplaintId())
						.getValue());
			}
			if (associatorView.getNonActionableId() != null
					&& associatorView.getNonActionableId() > 0) {
				associatorView
						.setNonActionableText(optionsBeanManager.findById(
								Constants.NON_ACTIONABLE_BEAN,
								associatorView.getNonActionableId()).getValue());
			}
		}
	}

	@Override
	protected ModelAndView processFinish(HttpServletRequest request,
			HttpServletResponse response, Object command,
			BindException exception) throws Exception {
		BusinessAssociatorView associatorView = (BusinessAssociatorView) command;
		Complaint complaint = (Complaint) WebUtils.getSessionAttribute(request,
				"initialcomplaint");

		if (associatorView.getBusiness().getId() == null
				|| associatorView.getBusiness().getId().equals("")) {
			logger.debug("=======>BEGIN ASSOCIATING A NEW BUSINESS<=======");
			if (associatorView.getBusiness().getBusinessCatLkp().getId() == null) {
				associatorView.getBusiness().setBusinessCatLkp(
						new BusinessCatLkp(optionsBeanManager.findById(
								Constants.BUS_CAT_BEAN, associatorView
										.getBusinessCategoryId())));
			}
			Business newBusiness = associatorView.getBusiness();
			/*
			 * Business newBusiness = new Business(
			 * associatorView.getBusinessCatLkp(), true,
			 * associatorView.getCountyLkp(), new StateLkp("OR", "Oregon"),
			 * associatorView.getBusinessName(),
			 * associatorView.getBusinessOwner(),
			 * associatorView.getBusinessOwnerTitle(),
			 * associatorView.getBusinessOwnerPhone(),
			 * associatorView.getBusinessOwnerEmail(),
			 * associatorView.getBusinessAddress1(),
			 * associatorView.getBusinessAddress2(),
			 * associatorView.getBusinessCity(),
			 * associatorView.getBusinessZip(),
			 * associatorView.getBusinessZipExt(),
			 * associatorView.getBusinessState(),
			 * associatorView.getBusinessPhone(),
			 * associatorView.getBusinessPhoneExt(),
			 * associatorView.getContactName(),
			 * associatorView.getContactEmail(), null);
			 */
			logger.debug("=======>Did we get the zip? "
							+ associatorView.getBusiness().getAddress()
									.getPostalCode());
			logger.debug("name: "
					+ associatorView.getBusiness().getBusinessName());
			logger.debug("getBusinessAddress1: "
					+ associatorView.getBusiness().getAddress().getAddress1());
			logger.debug("getBusinessCity: "
					+ associatorView.getBusiness().getAddress().getCity());
			logger.debug("getBusinessState: "
					+ associatorView.getBusiness().getAddress().getStateId());
			logger
					.debug("getBusinessZip: "
							+ associatorView.getBusiness().getAddress()
									.getPostalCode());
			logger.debug("getStateLkp: "
					+ associatorView.getBusiness().getAddress().getStateId());
			logger.debug("getCountyLkp: "
					+ associatorView.getBusiness().getAddress().getCountyId());
			logger.debug("active: " + associatorView.getBusiness().isActive());
			logger.debug("parentcontact: "
					+ associatorView.getBusiness().isParentAsContact());
			logger
					.debug("And now from the business: "
							+ newBusiness.toString());
			logger.debug("Now to save the business and do the logic...");
			Business business = businessManager.save(newBusiness);
			// process: if complaint is set to non-actionable:
			if (!associatorView.isActionable()) {
				complaint.setActionable(false);
				complaint.setFirstValidComplaint(false);
				// if non-actionableReason='Exempt Business', set
				// status='Valid Exempt Complaint'
				if (associatorView.getNonActionableId() == 1) {
					complaint.setComplaintStatusId(Long.valueOf(14));
				}
				// if non-actionableReason='Not Valid, set status='InValid
				// Complaint'
				if (associatorView.getNonActionableId() == 2) {
					complaint.setComplaintStatusId(Long.valueOf(13));
				}
				// Note: no grace period for first complaint/new Business
			}
			// process: if complaint is set to actionable
			if (associatorView.isActionable()) {
				complaint.setNatureOfComplaintId(associatorView
						.getNatureOfComplaintId());
				complaint.setActionable(true);
				complaint.setFirstValidComplaint(true);
			}
			complaint.setBusiness(business);
			complaintManager.save(complaint);
			business.addComplaint(complaint);
			logger.debug("COMPLAINT SAVED FOR NEW BUSINESS: "
					+ business.getBusinessName());
			logger.debug("====>END ASSOCIATING A NEW BUSINESS<====");
		} else {
			logger.debug("BEGIN ASSOCIATING AN EXISTING BUSINESS!!!");
			Business business = businessManager.get(associatorView
					.getBusiness().getId());
			logger.debug("here is the existing business: "
					+ business.getBusinessName());
			// the following are values that may have changed and/or added
			// during the wizard
			business.setContactName(associatorView.getBusiness()
					.getContactName());
			business.setContactName(associatorView.getBusiness()
					.getContactName());
			business.setContactEmail(associatorView.getBusiness()
					.getContactEmail());
			business.setContactTitle(associatorView.getBusiness()
					.getContactTitle());
			business.setBusinessPhoneExt(associatorView.getBusiness()
					.getBusinessPhoneExt());

			if (!associatorView.isActionable()) {
				if (associatorView.getNonActionableId() == 3) {
					// if non-actionableReason='Grace Period', set status='Grace
					// Period'
					complaint.setComplaintStatusId(Long.valueOf(3));
					complaint.setActionable(false);
				}
				if (associatorView.getNonActionableId() == 1) {
					// if non-actionableReason='Exempt Business', set
					// status='Valid Exempt Complaint'
					complaint.setComplaintStatusId(Long.valueOf(14));
					complaint.setActionable(false);
				}
				if (associatorView.getNonActionableId() == 2) {
					// if non-actionableReason='Not Valid', set status='InValid
					// Complaint'
					complaint.setComplaintStatusId(Long.valueOf(13));
					complaint.setActionable(false);
				}
			}
			if (associatorView.isActionable()) {
				complaint.setNatureOfComplaintId(associatorView
						.getNatureOfComplaintId());
				// get list of existing complaints for business
				List<Complaint> complaints = business.getComplaints();
				logger
						.debug("=================Existing Business Complaints=====================");
				logger.debug("complaint list size: " + complaints.size());
				if (complaints.size() == 0) {
					complaint.setActionable(true);
					complaint.setFirstValidComplaint(true);
					complaint.setComplaintStatusId(Long.valueOf(1));
				} else {// this is where we set the status based on existing
					// complaints
					for (Complaint existing : complaints) {
						logger.debug("===>is business first valid? "
								+ existing.isFirstValidComplaint());
						if (existing.isFirstValidComplaint()) {
							complaint.setComplaintStatusId(Long.valueOf(4));
							complaint.setActionable(true);
							complaint.setFirstValidComplaint(false);
							break;
						} else {
							complaint.setComplaintStatusId(Long.valueOf(1));
							complaint.setActionable(true);
							complaint.setFirstValidComplaint(true);
						}
					}
				}
				logger
						.debug("=============End Existing Business Complaints=====================");
			}
			complaint.setBusiness(business);
			Complaint c = complaintManager.save(complaint);
			logger.debug("SAVED COMPLAINT: " + c.getId());
			business.addComplaint(c);
			businessManager.save(business);

			logger.debug("SAVED EXISTING BUSINESS  "
					+ business.getBusinessName());
		}
		cleanSession(request);
		return new ModelAndView(getSuccessView());
	}

	/**
	 * Validates each page of the wizard individually. Overrides method
	 * validatePage(Object command, Errors errors, int page). This has to be
	 * called explicitly so that validation does not occur when using back
	 * buttons.
	 * 
	 * @param command
	 * @param errors
	 * @param page
	 * @param request
	 */
	protected void validatePage(Object command, Errors errors, int page,
			HttpServletRequest request) {
		BusinessAssociatorView associatorView = (BusinessAssociatorView) command;
		BusinessAssociatorValidator validator = (BusinessAssociatorValidator) getValidator();
		logger.debug("=======================================================");
		logger.debug("validating page: " + page);
		logger.debug("=======================================================");
		if (page == 1 && request.getParameter("_target3") != null) {
			validator.validateBusinessChecked(associatorView, errors);
		}
		if (page == 3 && request.getParameter("_target4") != null) {
			logger.debug("validating step 4...");
			validator.validateBusinessFields(associatorView, errors);
		}
		if (page == 4 && request.getParameter("_target5") != null) {
			validator.validateActionableStatus(associatorView, errors);
		}
	}

	protected ModelAndView processCancel(HttpServletRequest request,
			HttpServletResponse response, Object command,
			BindException exception) throws Exception {
		logger.debug("processing CANCEL");
		cleanSession(request);
		return new ModelAndView("redirect:/actionItems.wems?tab=actionItems");
	}

	private String getSuccessView() {
		return getPages()[getPages().length - 1];
	}

	private void cleanSession(HttpServletRequest request) {
		// now clean up the session
		request.getSession().removeAttribute("countyList");
		request.getSession().removeAttribute("nonActionableList");
		request.getSession().removeAttribute("natureOfComplaintList");
		request.getSession().removeAttribute("businessCategoryList");
		request.getSession().removeAttribute("businessList");
		request.getSession().removeAttribute("initialcomplaint");
		request.getSession().removeAttribute("complaintList");
	}

	private Object convertComplaintToView(Complaint complaint,
			BusinessAssociatorView view) {
		if (view.getBusiness() == null) {
			view.setBusiness(new Business());
		}
		view.getBusiness().setBusinessName(
				complaint.getInitialComplaint().getBusinessName());
		view.setBusinessCategoryId(complaint.getInitialComplaint()
				.getBusinessCategoryId());
		// TODO convert from BusinessCatLkp
		logger.debug("HERE IS THE BUSCATID: " + view.getBusinessCategoryId());
		if (view.getBusinessCategoryId() == 0) {
			view.getBusiness().setBusinessCatLkp(new BusinessCatLkp());
		} else {
			view.getBusiness()
					.setBusinessCatLkp(
							new BusinessCatLkp(optionsBeanManager.findById(
									Constants.BUS_CAT_BEAN, complaint
											.getInitialComplaint()
											.getBusinessCategoryId())));
		}
		view.getBusiness().getAddress().setAddress1(
				complaint.getInitialComplaint().getAddress().getAddress1());
		view.getBusiness().getAddress().setAddress2(
				complaint.getInitialComplaint().getAddress().getAddress2());
		view.getBusiness().getAddress().setCity(
				complaint.getInitialComplaint().getAddress().getCity());
		view.getBusiness().getAddress().setPostalCode(
				complaint.getInitialComplaint().getAddress().getPostalCode());
		view.getBusiness().setBusinessPhone(
				complaint.getInitialComplaint().getBusinessPhone());
		view.getBusiness().setBusinessPhoneExt(
				complaint.getInitialComplaint().getBusinessPhoneExt());
		view.setCountyId(complaint.getInitialComplaint().getAddress().getCountyId());
		view.getBusiness().getAddress().setCountyId(complaint.getInitialComplaint()
								.getAddress().getCountyId());
		view.setComplaintDate(complaint.getComplaintDate());
		view.setComplaintText(complaint.getComplaintText());
		return view;
	}

	protected void initBinder(HttpServletRequest request,
			ServletRequestDataBinder binder) {
		// convert java.util.Date
		SimpleDateFormat dateFormat = new SimpleDateFormat("mm/dd/yyyy");
		dateFormat.setLenient(false);
		binder.registerCustomEditor(Date.class, null, new CustomDateEditor(
				dateFormat, true));

		// convert java.lang.Long
		binder.registerCustomEditor(Long.class, null, new CustomNumberEditor(
				Long.class, null, true));
	}

	// do the wiring here
	public void setComplaintManager(ComplaintManager complaintManager) {
		this.complaintManager = complaintManager;
	}

	public void setBusinessManager(BusinessManager businessManager) {
		this.businessManager = businessManager;
	}

	public void setOptionsBeanManager(
			OptionsBeanLookupManager optionsBeanManager) {
		this.optionsBeanManager = optionsBeanManager;
	}

	public void setEmailManager(EmailManager emailManager) {
		this.emailManager = emailManager;
	}
}
